﻿using System.IO;
using System.Text;

using Moq;
using NUnit.Framework;

using Uhi.Libraries.Test;
using Uhi.Libraries.Test.Files;

using Uhi.Applications.FileAid.Model;
using Uhi.Applications.FileAid.ViewModel;

namespace FileAidTest.ViewModel
{
    [TestFixture]
    public class RecordViewModelTest
    {
        #region RecordInfo

        #region 正常ケース
        [Test]
        public void RecordInfo_正常ケース()
        {
            var mock = new Mock<IRecordInfo>();
            var vm = new RecordViewModel(mock.Object);
            (vm.AsDynamic().RecordInfo as IRecordInfo).Is(mock.Object);
        }
        #endregion

        #endregion

        #region Index

        #region 正常ケース
        [Test]
        public void Index_正常ケース()
        {
            var mock = new Mock<IRecordInfo>();
            mock.Setup(m => m.Line).Returns(0);

            var vm = new RecordViewModel(mock.Object);
            vm.Index.Is(1);
        }
        #endregion

        #endregion

        #region Encode

        #region 正常ケース
        [Test]
        public void Encode_正常ケース()
        {
            var mock = new Mock<IRecordInfo>();
            var vm = new RecordViewModel(mock.Object);
            var encode = Encoding.UTF32;
            vm.AsDynamic().Encode = encode;
            (vm.AsDynamic().Encode as Encoding).Is(encode);
        }
        #endregion

        #endregion

        #region Record

        #region Get

        #region 正常ケース
        [Test]
        public void Record_Get_正常ケース()
        {
            var encode = Encoding.Default;
            var data = "aaaaa";

            var mock = new Mock<IRecordInfo>();
            mock.Setup(m => m.Record).Returns(encode.GetBytes(data));

            var rec = new RecordViewModel(mock.Object);
            rec.AsDynamic().Encode = encode;
            rec.Record.Is(data);
        }
        #endregion

        #region 制御文字は空白に置き換える
        [Test]
        public void Record_Get_制御文字は空白に置き換える()
        {
            var encode = Encoding.Default;
            var data = "a\0a\ta\ra\na";

            var mock = new Mock<IRecordInfo>();
            mock.Setup(m => m.Record).Returns(encode.GetBytes(data));

            var rec = new RecordViewModel(mock.Object);
            rec.AsDynamic().Encode = encode;
            rec.Record.Is(data);
        }
        #endregion

        #endregion

        #region Set

        #region 正常ケース
        [Test]
        public void Record_Set_正常ケース()
        {
            var encode = Encoding.Default;
            var length = 5;

            var mock = new Mock<IRecordInfo>();
            mock.Setup(m => m.Length).Returns(length);
            mock.SetupProperty(m => m.Record);
            mock.Object.Record = encode.GetBytes("aaaaa");

            var vm = new RecordViewModel(mock.Object);
            vm.AsDynamic().Encode = encode;

            vm.Record = "abcde";

            mock.Object.Record.Is(encode.GetBytes("abcde"));
        }
        #endregion

        #region レコード長が短い
        [Test]
        public void Record_Set_レコード長が短い()
        {
            var encode = Encoding.Default;
            var length = 5;

            var mock = new Mock<IRecordInfo>();
            mock.Setup(m => m.Length).Returns(length);
            mock.SetupProperty(m => m.Record);
            mock.Object.Record = encode.GetBytes("aaaaa");

            var vm = new RecordViewModel(mock.Object);
            vm.AsDynamic().Encode = encode;

            vm.Record = "abc";

            mock.Object.Record.Is(encode.GetBytes("abc  "));
        }
        #endregion

        #region レコード長が長い
        [Test]
        public void Record_Set_レコード長が長い()
        {
            var encode = Encoding.Default;
            var length = 5;

            var mock = new Mock<IRecordInfo>();
            mock.Setup(m => m.Length).Returns(length);
            mock.SetupProperty(m => m.Record);
            mock.Object.Record = encode.GetBytes("aaaaa");

            var vm = new RecordViewModel(mock.Object);
            vm.AsDynamic().Encode = encode;

            vm.Record = "abcdefg";

            mock.Object.Record.Is(encode.GetBytes("abcde"));
        }
        #endregion

        #region 制御文字が空白に書き換えられないこと
        [Test]
        public void Record_Set_制御文字が空白に書き換えられないこと()
        {
            var encode = Encoding.Default;
            var length = 5;

            var mock = new Mock<IRecordInfo>();
            mock.Setup(m => m.Length).Returns(length);
            mock.SetupProperty(m => m.Record);
            mock.Object.Record = encode.GetBytes("\0\t\n\r\v");

            var vm = new RecordViewModel(mock.Object);
            vm.AsDynamic().Encode = encode;

            vm.Record = "\0\ta\r\v";

            mock.Object.Record.Is(encode.GetBytes("\0\ta\r\v"));
        }
        #endregion

        #region 変更通知のテスト
        [Test]
        public void Record_Set_変更通知のテスト()
        {
            var encode = Encoding.Default;
            var length = 5;

            var mock = new Mock<IRecordInfo>();
            mock.Setup(m => m.Length).Returns(length);
            mock.SetupProperty(m => m.Record);
            mock.Object.Record = encode.GetBytes("aaaaa");

            var vm = new RecordViewModel(mock.Object);
            vm.AsDynamic().Encode = encode;
            vm.TraceNotified(() => vm.Record);
            vm.TraceNotified(() => vm.HexRecord);

            vm.Record = "abcde";

            mock.Object.Record.Is(encode.GetBytes("abcde"));
            vm.VerifyAllNotified();
        }
        #endregion

        #endregion

        #endregion

        #region HexRecord

        #region Get

        #region 正常ケース
        [Test]
        public void HexRecord_Get_正常ケース()
        {
            var mock = new Mock<IRecordInfo>();
            mock.Setup(m => m.Record).Returns(Encoding.Default.GetBytes("11111"));

            var vm = new RecordViewModel(mock.Object);
            vm.HexRecord.Is("3131313131");
        }
        #endregion

        #endregion

        #region Set

        #region 正常ケース
        [Test]
        public void HexRecord_Set_正常ケース()
        {
            var mock = new Mock<IRecordInfo>();
            mock.Setup(m => m.Length).Returns(5);
            mock.SetupProperty(m => m.Record);
            mock.Object.Record = Encoding.Default.GetBytes("11111");

            var vm = new RecordViewModel(mock.Object);

            vm.HexRecord = "3132333435";

            mock.Object.Record.Is(Encoding.Default.GetBytes("12345"));
        }
        #endregion

        #region レコード長が短い
        [Test]
        public void HexRecord_Set_レコード長が短い()
        {
            var mock = new Mock<IRecordInfo>();
            mock.Setup(m => m.Length).Returns(5);
            mock.SetupProperty(m => m.Record);
            mock.Object.Record = Encoding.Default.GetBytes("11111");

            var vm = new RecordViewModel(mock.Object);

            vm.HexRecord = "3132333";

            mock.Object.Record.Is(Encoding.Default.GetBytes("1230\0"));
        }
        #endregion

        #region レコード長が長い
        [Test]
        public void HexRecord_Set_レコード長が長い()
        {
            var mock = new Mock<IRecordInfo>();
            mock.Setup(m => m.Length).Returns(5);
            mock.SetupProperty(m => m.Record);
            mock.Object.Record = Encoding.Default.GetBytes("11111");

            var vm = new RecordViewModel(mock.Object);

            vm.HexRecord = "3132333435363";

            mock.Object.Record.Is(Encoding.Default.GetBytes("12345"));
        }
        #endregion

        #region 変更通知のテスト
        [Test]
        public void HexRecord_Set_変更通知のテスト()
        {
            var mock = new Mock<IRecordInfo>();
            mock.Setup(m => m.Length).Returns(5);
            mock.SetupProperty(m => m.Record);
            mock.Object.Record = Encoding.Default.GetBytes("11111");

            var vm = new RecordViewModel(mock.Object);
            vm.TraceNotified(() => vm.Record);
            vm.TraceNotified(() => vm.HexRecord);

            vm.HexRecord = "3132333435";

            mock.Object.Record.Is(Encoding.Default.GetBytes("12345"));
            vm.VerifyAllNotified();
        }
        #endregion

        #endregion

        #endregion

        #region CaretIndex

        #region 正常ケース
        [Test]
        public void CaretIndex_正常ケース()
        {
            var mock = new Mock<IRecordInfo>();
            var vm = new RecordViewModel(mock.Object);
            vm.CaretIndex = 1;
            vm.CaretIndex.Is(1);
        }
        #endregion

        #region 変更通知のテスト
        [Test]
        public void CaretIndex_変更通知のテスト()
        {
            var mock = new Mock<IRecordInfo>();
            var vm = new RecordViewModel(mock.Object);
            vm.TraceNotified(() => vm.CaretIndex);

            vm.CaretIndex = 1;
            vm.CaretIndex.Is(1);

            vm.VerifyAllNotified();
        }
        #endregion

        #endregion

        #region HexCaretIndex

        #region 正常ケース
        [Test]
        public void HexCaretIndex_正常ケース()
        {
            var mock = new Mock<IRecordInfo>();
            var vm = new RecordViewModel(mock.Object);
            vm.HexCaretIndex = 1;
            vm.HexCaretIndex.Is(1);
        }
        #endregion

        #region 変更通知のテスト
        [Test]
        public void HexCaretIndex_変更通知のテスト()
        {
            var mock = new Mock<IRecordInfo>();
            var vm = new RecordViewModel(mock.Object);
            vm.TraceNotified(() => vm.HexCaretIndex);

            vm.HexCaretIndex = 1;
            vm.HexCaretIndex.Is(1);

            vm.VerifyAllNotified();
        }
        #endregion

        #endregion

        #region GetRecords

        #region GetRecords(string, int, string)

        #region 正常ケース
        [Test]
        public void GetRecords_正常ケース()
        {
            var dir = Path.Combine(Path.GetTempPath(), "RecordViewModelTest");
            var file = "foo.txt";
            var txt = new Txt(dir, file, "1111122222333334444455555");

            using (txt)
            {
                txt.Setup();

                var recs = RecordViewModel.GetRecords(Path.Combine(dir, file), 5, Encoding.Default.WebName);
                recs.Length.Is(5);
                recs[0].Record.Is("11111");
                recs[1].Record.Is("22222");
                recs[2].Record.Is("33333");
                recs[3].Record.Is("44444");
                recs[4].Record.Is("55555");
            }
        }
        #endregion

        #region ファイルが存在しない
        [Test]
        public void GetRecords_ファイルが存在しない()
        {
            var recs = RecordViewModel.GetRecords("foo.txt", 5, Encoding.Default.WebName);
            recs.IsNull();
        }
        #endregion

        #region レコード長があわない場合
        [Test]
        public void GetRecords_レコード長があわない場合()
        {
            var dir = Path.Combine(Path.GetTempPath(), "RecordViewModelTest");
            var file = "foo.txt";
            var txt = new Txt(dir, file, "11111222223333344444555");

            using (txt)
            {
                txt.Setup();

                var recs = RecordViewModel.GetRecords(Path.Combine(dir, file), 5, Encoding.Default.WebName);
                recs.Length.Is(5);
                recs[0].Record.Is("11111");
                recs[1].Record.Is("22222");
                recs[2].Record.Is("33333");
                recs[3].Record.Is("44444");
                recs[4].Record.Is("555\0\0");
            }
        }
        #endregion

        #region レコード長がゼロ
        [Test]
        public void GetRecords_レコード長がゼロ()
        {
            var dir = Path.Combine(Path.GetTempPath(), "RecordViewModelTest");
            var file = "foo.txt";
            var txt = new Txt(dir, file, "1111122222333334444455555");

            using (txt)
            {
                txt.Setup();

                var recs = RecordViewModel.GetRecords(Path.Combine(dir, file), 0, Encoding.Default.WebName);
                recs.Length.Is(0);
            }
        }
        #endregion

        #endregion

        #region GetRecord(string, int, string, string)

        #region 正常ケース
        [Test]
        public void GetRecord_string_int_string_string_正常ケース()
        {
            var dir = Path.Combine(Path.GetTempPath(), "RecordViewModelTest");
            var file = "foo.txt";
            var txt = new Txt(dir, file, "1\r\n22\r\n333\r\n4444\r\n55555\r\n\r\n");

            using (txt)
            {
                txt.Setup();

                var recs = RecordViewModel.GetRecords(Path.Combine(dir, file), 5, Encoding.Default.WebName, "\r\n");
                recs.Length.Is(7);
                recs[0].Record.Is("1\r\n");
                recs[1].Record.Is("22\r\n");
                recs[2].Record.Is("333\r\n");
                recs[3].Record.Is("4444\r");
                recs[4].Record.Is("\n5555");
                recs[5].Record.Is("5\r\n");
                recs[6].Record.Is("\r\n");
            }
        }
        #endregion

        #region ファイルが存在しない
        [Test]
        public void GetRecord_string_int_string_string_ファイルが存在しない()
        {
            var recs = RecordViewModel.GetRecords("foo.txt", 5, Encoding.Default.WebName, "\r\n");
            recs.IsNull();
        }
        #endregion

        #region レコード長があわない場合
        [Test]
        public void GetRecord_string_int_string_string_レコード長があわない場合()
        {
            var dir = Path.Combine(Path.GetTempPath(), "RecordViewModelTest");
            var file = "foo.txt";
            var txt = new Txt(dir, file, "11111222223333344444555");

            using (txt)
            {
                txt.Setup();

                var recs = RecordViewModel.GetRecords(Path.Combine(dir, file), 5, Encoding.Default.WebName, "\r\n");
                recs.Length.Is(5);
                recs[0].Record.Is("11111");
                recs[1].Record.Is("22222");
                recs[2].Record.Is("33333");
                recs[3].Record.Is("44444");
                recs[4].Record.Is("555\0\0");
            }
        }
        #endregion

        #region レコード長がゼロ
        [Test]
        public void GetRecord_string_int_string_string_レコード長がゼロ()
        {
            var dir = Path.Combine(Path.GetTempPath(), "RecordViewModelTest");
            var file = "foo.txt";
            var txt = new Txt(dir, file, "1111122222333334444455555");

            using (txt)
            {
                txt.Setup();

                var recs = RecordViewModel.GetRecords(Path.Combine(dir, file), 0, Encoding.Default.WebName, "\r\n");
                recs.Length.Is(0);
            }
        }
        #endregion

        #endregion

        #endregion

        #region Save

        #region 正常ケース
        [Test]
        public void Save_正常ケース()
        {
            var mock = new Mock<IRecordInfo>();
            mock.Setup(m => m.Save());

            var vm = new RecordViewModel(mock.Object);
            vm.Save();

            mock.Verify(m => m.Save());
        }
        #endregion

        #endregion

        #region SaveAs

        #region 正常ケース
        [Test]
        public void SaveAs_正常ケース()
        {
            var path = "foo.txt";
            var mock = new Mock<IRecordInfo>();
            mock.Setup(m => m.SaveAs(path));

            var vm = new RecordViewModel(mock.Object);
            vm.SaveAs(path);

            mock.Verify(m => m.SaveAs(path));
        }
        #endregion

        #endregion
    }
}
